/** infer可以用于提取类型的一部分 */



//--------------------------数组类型--------------------------------------

// 数组类型想提取第一个元素
type GetFirst<Arr extends unknown[]> = Arr extends [infer T, ...unknown[]] ? T : never;
type GetFristR = GetFirst<[1, 3, 4]>

// 提取最后一个元素
type GetLast<Arr extends unknown[]> = Arr extends [...unknown[], infer T] ? T : never;
type GetLastR = GetLast<[12, 3, 4]>

// 提取除最后一个元素，剩余的数组
type GetPopArr<Arr extends unknown[]> = Arr extends [...infer T, unknown] ? T : never;
type GetPopArrR = GetPopArr<[12, 4, 5, 61, 23]>

// 提取除了第一个，剩余的数组
type GetShiftArr<Arr extends unknown[]> = Arr extends [unknown, ...infer T] ? T : never;
type GetShiftArrR = GetShiftArr<[12, 43, 5, 65,4, 32]>

//--------------------------字符串类型--------------------------------------

// 判断字符串是否是以某个前缀开头
type GetStartWith<Str extends string, Prefix extends string> = Str extends `${Prefix}${string}` ? true : false;
type GetStartWithR = GetStartWith<"dafaj", "d">
type GetStartWithR1 = GetStartWith<"dafaj", "1d">

// 实现字符串替换
type GetReplace<Str extends string, From extends string, To extends string> = Str extends `${infer P}${From}${infer L}` ? `${P}${To}${L}` : never;
type GetReplaceR = GetReplace<"abcdefghijklmn", "defghi", "123">

// 实现去除字符串尾部空白符
type GetTrimRight<Str extends string> = Str extends `${infer T}${" " | "\n" | "\t"}` ? GetTrimRight<T> : Str;  // 因为我们不知道有多少空白符。所以需要用到递归
type GetTrimR = GetTrimRight<"  dfdjlka  ">

// 去除字符串左侧空白符
type GetTrimLeft<Str extends string> = Str extends `${" " | "\n" | "\s"}${infer T}` ? GetTrimLeft<T> : Str;
type GetTrimLeftR = GetTrimLeft<"     daflkdjkjd  ">

type GetTrim = GetTrimRight<GetTrimLeft<"     daflkdjkjd  ">> // 实现了去除头尾空白

//--------------------------函数类型--------------------------------------

type Fn = (age: number, name: string) => void;
// 获取函数传入的参数类型。
type GetParam<Fn extends Function> = Fn extends (...args: infer Args) => unknown ? Args : never; 
type GetParamR = GetParam<Fn>

// 获取函数的返回值类型
type GetReturnType<Fn extends Function> = Fn extends (...args: any[]) => infer Return ? Return : never;
function fn1() {
  return 123;
}
type GetReturnTypeR = GetReturnType<typeof fn1>;

// 获取class中this指向。没有get到用处，我的理解是和GetParam是一样的
class Dog {
  name: string;
  constructor() {
    this.name = "hello";
  }
  getName(this: Dog) {
    return `我的名字叫:${this.name}`;
  }
}
const dog = new Dog();
type GetThisParameterType<T> = T extends (this: infer ThisType, ...args: any[]) => any ? ThisType : unknown;
type GetThisParameterTypeR = GetThisParameterType<typeof dog.getName>


//-------------------------- 构造器 --------------------------------------
/**
 * 构造器类型可以用interface声明，使用new():xx语法
 * 比如下面，PersonConstructor返回的就是Person类型的实例对象，同样的可以通过类型匹配取出来
 */
interface Person {
  name: string;
}

interface PersonConstructor {
  new(name: string): Person;
}

// 提取构造函数的返回值
type GetInstanceType<ConstructorType extends new(...arg: any) =>any> = ConstructorType extends new(...args: any) => infer InstanceType ? InstanceType : never;
type GetInstanceTypeR = GetInstanceType<PersonConstructor>

// 同样的，去构造函数的param
type GetConstructorParams<ConstructorType extends new(...args: any) =>any> = ConstructorType extends new(...args: infer P) => any ? P : never; 
type GetConstructorParamsR = GetConstructorParams<PersonConstructor>

//-------------------------- 索引类型 --------------------------------------

// 提取React的Props中 ref类型

type GetRefType<Props> = Props extends { ref?: infer Ref | undefined } ? Ref : never;
type GetRefTypeR = GetRefType<{ name: 123 }>
type GetRefTypeR1 = GetRefType<{ name: 123, ref: 12 }>




























